package org.unidata.mdm.meta.type.model.entities;

import static org.unidata.mdm.meta.type.model.ModelNamespace.META_MODEL_NAMESPACE;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.unidata.mdm.core.type.model.source.CustomProperty;
import org.unidata.mdm.core.type.model.source.VersionedObject;
import org.unidata.mdm.meta.type.model.MetaModelEntity;
import org.unidata.mdm.meta.type.model.PeriodBoundary;
import org.unidata.mdm.meta.type.model.attributes.ArrayMetaModelAttribute;
import org.unidata.mdm.meta.type.model.attributes.AttributeGroup;
import org.unidata.mdm.meta.type.model.attributes.SimpleMetaModelAttribute;
import org.unidata.mdm.meta.type.model.merge.MergeSettings;

import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;

public abstract class AbstractEntity<X extends AbstractEntity<X>> extends VersionedObject<X> implements MetaModelEntity {
    /**
     * GSVUID.
     */
    private static final long serialVersionUID = 8585353285853721016L;

    @JacksonXmlProperty(isAttribute = true)
    private String name;

    @JacksonXmlProperty(isAttribute = true)
    private String displayName;

    @JacksonXmlProperty(isAttribute = true)
    private String description;

    @JacksonXmlProperty(namespace = META_MODEL_NAMESPACE)
    private MergeSettings mergeSettings;

    @JacksonXmlProperty(namespace = META_MODEL_NAMESPACE)
    private PeriodBoundary validityPeriod;

    @JacksonXmlProperty(namespace = META_MODEL_NAMESPACE)
    private List<SimpleMetaModelAttribute> simpleAttribute;

    @JacksonXmlProperty(namespace = META_MODEL_NAMESPACE)
    private List<ArrayMetaModelAttribute> arrayAttribute;

    @JacksonXmlProperty(namespace = META_MODEL_NAMESPACE)
    private List<AttributeGroup> attributeGroups;

    @JacksonXmlProperty(namespace = META_MODEL_NAMESPACE)
    private List<RelationGroup> relationGroups;

    @JacksonXmlProperty(namespace = META_MODEL_NAMESPACE)
    private List<CustomProperty> customProperties;

    @Override
    public String getName() {
        return name;
    }

    @Override
    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String getDisplayName() {
        return displayName;
    }

    @Override
    public void setDisplayName(String displayName) {
        this.displayName = displayName;
    }

    @Override
    public String getDescription() {
        return description;
    }

    @Override
    public void setDescription(String description) {
        this.description = description;
    }

    @Override
    public List<SimpleMetaModelAttribute> getSimpleAttribute() {
        if (simpleAttribute == null) {
            simpleAttribute = new ArrayList<>();
        }
        return simpleAttribute;
    }

    @Override
    public void setSimpleAttribute(List<SimpleMetaModelAttribute> simpleAttribute) {
        withSimpleAttribute(simpleAttribute);
    }

    @Override
    public List<ArrayMetaModelAttribute> getArrayAttribute() {
        if (arrayAttribute == null) {
            arrayAttribute = new ArrayList<>();
        }
        return arrayAttribute;
    }

    @Override
    public void setArrayAttribute(List<ArrayMetaModelAttribute> arrayAttribute) {
        withArrayAttribute(arrayAttribute);
    }

    @Override
    public MergeSettings getMergeSettings() {
        return mergeSettings;
    }

    @Override
    public void setMergeSettings(MergeSettings mergeSettings) {
        this.mergeSettings = mergeSettings;
    }

    @Override
    public PeriodBoundary getValidityPeriod() {
        return validityPeriod;
    }

    @Override
    public void setValidityPeriod(PeriodBoundary validityPeriod) {
        this.validityPeriod = validityPeriod;
    }

    @Override
    public List<AttributeGroup> getAttributeGroups() {
        if (attributeGroups == null) {
            attributeGroups = new ArrayList<>();
        }
        return attributeGroups;
    }

    public void setAttributeGroups(List<AttributeGroup> attributeGroups) {
        withAttributeGroups(attributeGroups);
    }

    @Override
    public List<RelationGroup> getRelationGroups() {
        if (relationGroups == null) {
            relationGroups = new ArrayList<>();
        }
        return relationGroups;
    }

    public void setRelationGroups(List<RelationGroup> relationGroups) {
        withRelationGroups(relationGroups);
    }

    @Override
    public List<CustomProperty> getCustomProperties() {
        if (customProperties == null) {
            customProperties = new ArrayList<>();
        }
        return customProperties;
    }

    @Override
    public void setCustomProperties(List<CustomProperty> customProperties) {
        withCustomProperties(customProperties);
    }

    public X withName(String value) {
        setName(value);
        return self();
    }

    public X withDisplayName(String value) {
        setDisplayName(value);
        return self();
    }

    public X withDescription(String value) {
        setDescription(value);
        return self();
    }

    public X withSimpleAttribute(SimpleMetaModelAttribute... values) {
        if (ArrayUtils.isNotEmpty(values)) {
            Collections.addAll(getSimpleAttribute(), values);
        }
        return self();
    }

    public X withSimpleAttribute(Collection<SimpleMetaModelAttribute> values) {
        if (CollectionUtils.isNotEmpty(values)) {
            getSimpleAttribute().addAll(values);
        }
        return self();
    }

    public X withArrayAttribute(ArrayMetaModelAttribute... values) {
        if (ArrayUtils.isNotEmpty(values)) {
            Collections.addAll(getArrayAttribute(), values);
        }
        return self();
    }

    public X withArrayAttribute(Collection<ArrayMetaModelAttribute> values) {
        if (CollectionUtils.isNotEmpty(values)) {
            getArrayAttribute().addAll(values);
        }
        return self();
    }

    public X withMergeSettings(MergeSettings value) {
        setMergeSettings(value);
        return self();
    }

    public X withValidityPeriod(PeriodBoundary value) {
        setValidityPeriod(value);
        return self();
    }

    public X withAttributeGroups(AttributeGroup... values) {
        if (ArrayUtils.isNotEmpty(values)) {
            Collections.addAll(getAttributeGroups(), values);
        }
        return self();
    }

    public X withAttributeGroups(Collection<AttributeGroup> values) {
        if (CollectionUtils.isNotEmpty(values)) {
            getAttributeGroups().addAll(values);
        }
        return self();
    }

    public X withRelationGroups(RelationGroup... values) {
        if (ArrayUtils.isNotEmpty(values)) {
            Collections.addAll(getRelationGroups(), values);
        }
        return self();
    }

    public X withRelationGroups(Collection<RelationGroup> values) {
        if (CollectionUtils.isNotEmpty(values)) {
            getRelationGroups().addAll(values);
        }
        return self();
    }

    public X withCustomProperties(CustomProperty... values) {
        if (ArrayUtils.isNotEmpty(values)) {
            Collections.addAll(getCustomProperties(), values);
        }
        return self();
    }

    public X withCustomProperties(Collection<CustomProperty> values) {
        if (CollectionUtils.isNotEmpty(values)) {
            getCustomProperties().addAll(values);
        }
        return self();
    }
}
